import {withLock} from "easylock";
import sample = require("lodash/sample");
import {InstanceType} from "typegoose";
import {ConsumeRecordModel} from "../../database/models/consumeRecord";
import {GamePrizeModel} from "../../database/models/gamePrize";
import {GiftState, MailModel, MailState, MailType} from "../../database/models/mail";
import {Player, PlayerModel} from "../../database/models/player";
import {Product, ProductModel} from "../../database/models/Product";
import {deleteProductStockSafely, ProductGroup, ProductGroupModel} from "../../database/models/ProductGroup";
import {InternalError} from "../error";
import {playerUseCoinOrGemOrPoint} from "./lipStickGame";

export class RotateEggGame {


  constructor(readonly player: InstanceType<Player>,
              readonly productGroup: InstanceType<ProductGroup>,
              readonly draws: any) {

  }

  async start() {

    const {player, productGroup, draws} = this

    return await withLock(player.id, async () => {

      const drawsFee = productGroup.priceInGem * draws;

      const {ok, consume} = await playerUseCoinOrGemOrPoint(player, drawsFee, productGroup.id, `rotateEgg`)
      if (!ok)
        throw InternalError('NO_ENOUGH_GEM')

      const gifts = []

      function levelFromDraws(ds: number) {
        if (ds === 10) return 4

        if (ds === 3) return 3

        if (ds === 1) {
          return Math.random() > 0.8 ? 2 : 1
        }
      }

      const productGroupOnStock = {level1: [], level2: [], level3: [], level4: []}
      let stock = 0
      const productGroupNow = await ProductGroupModel.findById(productGroup.id)
        .populate(`level1`)
        .populate(`level2`)
        .populate(`level3`)
        .populate(`level4`)
      for (let i = 0; i < 4; i++) {
        for (const it of (productGroupNow[`level${i + 1}`] as Array<InstanceType<Product>>)) {
          if (it.stock > 0) {
            productGroupOnStock[`level${i + 1}`].push(it)
            stock += it.stock
          }
        }
      }
      if (stock < draws) {
        await ConsumeRecordModel.findByIdAndUpdate(consume, {$set: {success: false}})
        await PlayerModel.findByIdAndUpdate(player.id, {$inc: {gem: drawsFee}})
        await ProductGroupModel.findByIdAndUpdate(productGroupNow.id, {$set: {state: `off`}})
        throw InternalError("NO_ON_STOCK")
      }

      if (productGroupOnStock[`level${levelFromDraws(draws)}`].length === 0) {
        await ConsumeRecordModel.findByIdAndUpdate(consume, {$set: {success: false}})
        await PlayerModel.findByIdAndUpdate(player.id, {$inc: {gem: drawsFee}})
        await ProductGroupModel.findByIdAndUpdate(productGroupNow.id, {$set: {state: `off`}})
        throw InternalError("NO_ON_STOCK")
      }
      gifts.push(sample(productGroupOnStock[`level${levelFromDraws(draws)}`]))

      for (let draw = 0; draw < draws - 1; draw++) {
        gifts.push(sample(productGroup.level1))
      }

      const result = await deleteProductStockSafely(gifts)
      if (!result || !result.ok || !result.successList) {
        await ConsumeRecordModel.findByIdAndUpdate(consume, {$set: {success: false}})
        await PlayerModel.findByIdAndUpdate(player.id, {$inc: {gem: drawsFee}})
        await ProductGroupModel.findByIdAndUpdate(productGroupNow.id, {$set: {state: `off`}})
        throw InternalError("NO_ON_STOCK")
      }

      await ProductGroupModel.findByIdAndUpdate(productGroup.id, {$inc: {hotNum: 1}})

      const successGift = []
      for (const productId of result.successList) {
        const p = await ProductModel.findById(productId)
        if (!p)
          continue
        await GamePrizeModel.create({
          player: player.id,
          product: p.id,
          productName: p.name,
          productModel: p.model,
          productDescription: p.description,
          productUrl: p.coverUrl,
          inviteBy: player.inviteBy,
          state: 'idle',
          createAt: new Date(),
          from: 'egg',
          selectState: `notAllowed`
        })
        successGift.push(p)
      }
      await MailModel.create({
        title: `扭蛋机奖品到账通知`,
        content: `扭蛋机奖励已经添加到您的奖品列表中`,
        to: player.id,
        type: MailType.NOTICE,
        giftState: GiftState.NOTALLOW,
        state: MailState.UNREAD
      })

      // 库存不够提前下架
      const productGroupOnStock1 = {level1: [], level2: [], level3: [], level4: []}
      let stock1 = 0
      const productGroupNow1 = await ProductGroupModel.findById(productGroup.id)
        .populate(`level1`)
        .populate(`level2`)
        .populate(`level3`)
        .populate(`level4`)
      for (let i = 0; i < 4; i++) {
        for (const it of (productGroupNow1[`level${i + 1}`] as Array<InstanceType<Product>>)) {
          if (it.stock > 0 && it.state !== `off`) {
            productGroupOnStock1[`level${i + 1}`].push(it)
            stock1 += it.stock
          }
        }
      }
      if (stock1 < 10)
        await ProductGroupModel.findByIdAndUpdate(productGroupNow1.id, {$set: {state: `off`}})

      return successGift
    })
  }
}
